package com.niiwoo.civet.trade.service.local.loan;

import com.alibaba.fastjson.JSONObject;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.RateConfigDTO;
import com.niiwoo.civet.trade.dto.common.BuildRepaymentDTO;
import com.niiwoo.civet.trade.dto.common.ProjectDTO;
import com.niiwoo.civet.trade.dto.request.loan.ConfirmLoanRepaymentPlanRequestDTO;
import com.niiwoo.civet.trade.dto.request.loan.ConfirmLoanRequestDTO;
import com.niiwoo.civet.trade.dto.request.loan.RepaymentPlanDTO;
import com.niiwoo.civet.trade.dto.response.loan.ConfirmResponseDTO;
import com.niiwoo.civet.trade.dto.response.loan.InvestUserInfoResponseDTO;
import com.niiwoo.civet.trade.enums.PeriodUnitEnum;
import com.niiwoo.civet.trade.enums.ProjectTypeEnum;
import com.niiwoo.civet.trade.enums.RepaymentTypeEnum;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.local.configure.TradeConfigLocalService;
import com.niiwoo.civet.trade.service.local.plan.AverageCapitalPlusInterest;
import com.niiwoo.civet.trade.service.local.plan.BorrowerInvestorRepaymentContext;
import com.niiwoo.civet.trade.service.local.project.ProjectLocalService;
import com.niiwoo.tripod.base.component.PrivacyMasks;
import com.niiwoo.tripod.provider.exception.BizException;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

/**
 * Created by lujing on 2017/12/7.
 */
@Slf4j
@Service
public class LoanConfirmService {
    @Autowired
    private RateConfigPercentMapperExt rateConfigPercentMapperExt;
    @Autowired
    private ProjectLocalService projectLocalService;
    @Autowired
    private TradeConfigLocalService tradeConfigLocalService;
    @Autowired
    private ProjectInvestOrderMapperExt projectInvestOrderMapperExt;
    @Autowired
    private RateConfigMapperExt rateConfigMapperExt;
    @Autowired
    private ProjectRateMapperExt projectRateMapperExt;
    @Autowired
    private ProjectMapperExt projectMapperExt;
    @Autowired
    private BorrowerInvestorRepaymentContext borrowerInvestorRepaymentContext;
    @Autowired
    private AverageCapitalPlusInterest averageCapitalPlusInterest;
    @Autowired
    private LoanBusinessInfoMapperExt loanBusinessInfoMapperExt;
    @Autowired
    PrivacyMasks privacyMasks;
    static final int PRECISION_TWO = 2;
    static final int PRECISION_FOUR = 4;
    static final int Month = 12;
    public ConfirmResponseDTO loanConfirm(ConfirmLoanRequestDTO loanConfirmRequestDTO) {
        JSONObject.toJSONString("砍头息参数" + loanConfirmRequestDTO);
        Assert.notNull(loanConfirmRequestDTO, "砍头息参数 build loanConfirm loanConfirmRequestDTO is null.");

        RateConfig rateConfig = rateConfigMapperExt.queryRateConfigByDeadline(loanConfirmRequestDTO.getLoanTerm(),loanConfirmRequestDTO.getConfigType());
        //还款总金额
        BigDecimal totalRepayAmount;
        //还款总利息
        BigDecimal totalInterest = BigDecimal.ZERO;
        //借款本金
        BigDecimal loanAmount = loanConfirmRequestDTO.getLoanAmount();
        //等额本息：每月还款额=〔贷款本金×月利率×（1＋月利率）＾还款月数〕÷〔（1＋月利率）＾还款月数－1〕
        //月利率
        BigDecimal loanInterestRate = rateConfig.getBorrowInterestRate().divide(new BigDecimal(12), MathContext.DECIMAL128);
        //1＋月利率
        BigDecimal third = new BigDecimal(1).add(loanInterestRate);
        //还款月数
        Integer loanTerm = loanConfirmRequestDTO.getLoanTerm();
        //如果是到期还本息
        Byte repaymentWay = rateConfig.getRepaymentMode();
        if (RepaymentTypeEnum.REPAY_PRINCIPAL_INTEREST_AT_TERM.getValue().equals(repaymentWay)) {

            totalInterest = loanInterestRate.multiply(new BigDecimal(loanConfirmRequestDTO.getLoanTerm())).multiply(loanAmount);

            totalRepayAmount = loanAmount.add(totalInterest);
        } else {
            //等额本息
            List<RepaymentPlanDTO> repaymentPlanDTOList = repaymentPlan(loanAmount, loanTerm, rateConfig);
            if (!repaymentPlanDTOList.isEmpty()) {
                for (RepaymentPlanDTO repaymentPlanDTO : repaymentPlanDTOList) {
                    //还款总利息=贷款额*贷款月数*月利率
                    totalInterest = totalInterest.add(repaymentPlanDTO.getInterest());
                }
            }
            //还款总额=借款额+总利息
            totalRepayAmount = loanAmount.add(totalInterest);
        }


        //平台管理费
        BigDecimal platformManageFee = BigDecimal.ZERO;
        //担保服务费
        BigDecimal guaranteServiceFee = BigDecimal.ZERO;

        //和融360合同的接口共用，所以这边判断一下projectId是不是为空，合同的需要传projectId,否则就是给借款详情用
        if (loanConfirmRequestDTO.getProjectId() == null) {
            platformManageFee = loanAmount.multiply(rateConfig.getPlatformManageFeeRate());
            guaranteServiceFee = loanAmount.multiply(rateConfig.getGuaranteeServiceFeeRate());
        } else {
            //借款详情的计算部分
            List<ProjectRate> projectRateList = projectRateMapperExt.queryProjectRateListOrderByCurrentPeriodAscByProjectIdAndBorrowUserId(loanConfirmRequestDTO.getProjectId(), loanConfirmRequestDTO.getUserId());
            if (projectRateList.size() == 0) {
                Project project = projectMapperExt.selectByPrimaryKey(loanConfirmRequestDTO.getProjectId());
                if (project != null) {
                    platformManageFee = loanAmount.multiply(project.getManageRate());
                    guaranteServiceFee = loanAmount.multiply(project.getGuaranteeRate());
                }
            } else {
                for (ProjectRate projectRate : projectRateList) {
                    platformManageFee = platformManageFee.add(projectRate.getPlatformManageFeePercent()
                            .multiply(rateConfig.getPlatformManageFeeRate()).multiply(loanAmount));
                    guaranteServiceFee = guaranteServiceFee.add(projectRate.getGuaranteeServiceFeePercent()
                            .multiply(rateConfig.getGuaranteeServiceFeeRate()).multiply(loanAmount));
                }
            }
        }

        //封装返回参数
        ConfirmResponseDTO confirmResponseDTO = new ConfirmResponseDTO();
        confirmResponseDTO.setLoanTerm(loanConfirmRequestDTO.getLoanTerm());
        confirmResponseDTO.setRepaymentWay(RepaymentTypeEnum.enumOf(rateConfig.getRepaymentMode()));
        confirmResponseDTO.setTotalRepayAmount(totalRepayAmount.add(guaranteServiceFee).add(platformManageFee).setScale(PRECISION_TWO, BigDecimal.ROUND_HALF_UP));
        confirmResponseDTO.setGuaranteServiceFee(guaranteServiceFee.setScale(PRECISION_TWO, BigDecimal.ROUND_HALF_UP));
        confirmResponseDTO.setPlatformManageFee(platformManageFee.setScale(PRECISION_TWO, BigDecimal.ROUND_HALF_UP));
        confirmResponseDTO.setLoanInterestFee(totalInterest.setScale(PRECISION_TWO, BigDecimal.ROUND_HALF_UP));
        confirmResponseDTO.setLoanInterestRate(rateConfig.getBorrowInterestRate());
        confirmResponseDTO.setLoanUsage(loanConfirmRequestDTO.getLoanUsage());
        confirmResponseDTO.setPlatformManageFeeRate(rateConfig.getPlatformManageFeeRate());

//        List<TradeConfigEnum> enums = new ArrayList<>();
//        if(loanConfirmRequestDTO.getConfigType().equals(RateConfigTypeEnum.CARD_NIU.getType())){
//            enums.add(TradeConfigEnum.CARDNIU_OVERDUEFEERATE);
//        }else {
//            enums.add(TradeConfigEnum.OVERDUEFEERATE);
//        }
//        Map<String, String> configMap = tradeConfigLocalService.selectTradeConfigByEmuns(enums);
//        String overdueFeeRate = null;
//        if(loanConfirmRequestDTO.getConfigType().equals(RateConfigTypeEnum.CARD_NIU.getType())){
//            overdueFeeRate = configMap.get(TradeConfigEnum.CARDNIU_OVERDUEFEERATE.getConfigKey());
//        }else{
//            overdueFeeRate = configMap.get(TradeConfigEnum.OVERDUEFEERATE.getConfigKey());
//        }
//        confirmResponseDTO.setOverdueFeeRate(new BigDecimal(overdueFeeRate).setScale(PRECISION_TWO, BigDecimal.ROUND_HALF_UP));

        confirmResponseDTO.setOverdueFeeRate(getOverdueFeeRate(ProjectTypeEnum.getEnum(loanConfirmRequestDTO.getConfigType())));

        //计算提现费用
        Map<String, String> configMap = tradeConfigLocalService.selectTradeConfigByEmuns(TradeConfigEnum.FASTWITHDRAWFEE); //提现费率-快速提现
        if (configMap.containsKey(TradeConfigEnum.FASTWITHDRAWFEE.getConfigKey())) {
        	BigDecimal withdrawFeeRate = new BigDecimal(configMap.get(TradeConfigEnum.FASTWITHDRAWFEE.getConfigKey()));
        	BigDecimal withdrawFee = loanConfirmRequestDTO.getLoanAmount().multiply(withdrawFeeRate);

        	confirmResponseDTO.setWithdrawFeeRate(withdrawFeeRate);
        	confirmResponseDTO.setWithdrawFee(withdrawFee.setScale(PRECISION_TWO, BigDecimal.ROUND_HALF_UP));
        }

        confirmResponseDTO.setHandAmount(loanAmount);
        confirmResponseDTO.setPlatformManageFeeRate(rateConfig.getPlatformManageFeeRate());
        confirmResponseDTO.setGuaranteeServiceFeeRate(rateConfig.getGuaranteeServiceFeeRate());
        return confirmResponseDTO;
    }

    private BigDecimal getOverdueFeeRate(ProjectTypeEnum projectType) {
    	if (projectType == null) {
    		throw new BizException("TRD60001"); //产品不存在
    	}

    	BigDecimal result = BigDecimal.ZERO;

    	List<TradeConfigEnum> enums = new ArrayList<>();
    	String overdueFeeRate = null;
        LoanBusinessInfo loanBusinessInfo = null;
        Map<String, String> configMap = null;
    	switch (projectType) {
    	case PERSONAL_SPEEDLOAN://极速借
    		enums.add(TradeConfigEnum.OVERDUEFEERATE);
    		configMap = tradeConfigLocalService.selectTradeConfigByEmuns(enums);
    		overdueFeeRate = configMap.get(TradeConfigEnum.OVERDUEFEERATE.getConfigKey());
    		break;
    	case CARD_NIU_LOAN://卡牛
    		enums.add(TradeConfigEnum.CARDNIU_OVERDUEFEERATE);
    		configMap = tradeConfigLocalService.selectTradeConfigByEmuns(enums);
    		overdueFeeRate = configMap.get(TradeConfigEnum.CARDNIU_OVERDUEFEERATE.getConfigKey());
    		break;
    	case SMALL_LOAN://小易贷
    	case SOCIAL_SECURITY_LOAN://社保贷
    	case CONSUME_LOAN://信用卡贷    		
    	case CREDIT_CARD_LOAN://信用卡贷
    		loanBusinessInfo = loanBusinessInfoMapperExt.selectByProductType(projectType.getValue());
    		return loanBusinessInfo.getOverDueFee();
    	default: //如果是不存在的产品直接抛出异常，产品罚息利率没配置
    		throw new BizException("TRD60002");
    	}

        if (overdueFeeRate != null && !"".equals(overdueFeeRate)) {
        	result = new BigDecimal(overdueFeeRate);
        }

        return result;
    }

    public ConfirmResponseDTO userLoanInfo(Long projectId) {
        Assert.notNull(projectId, "projectId is null");
        ProjectDTO projectDTO = projectLocalService.selectProjectById(projectId);
        if (projectDTO != null) {
            ConfirmLoanRequestDTO loanConfirmRequestDTO = new ConfirmLoanRequestDTO();
            loanConfirmRequestDTO.setLoanAmount(projectDTO.getHandAmount());
            loanConfirmRequestDTO.setLoanTerm(projectDTO.getDeadline());
            loanConfirmRequestDTO.setConfigType(ProjectTypeEnum.PERSONAL_SPEEDLOAN.getValue());

            ConfirmResponseDTO confirmResponseDTO = loanConfirm(loanConfirmRequestDTO);
            confirmResponseDTO.setFullTime(projectDTO.getFullSuccessTime());
            //合同的担保费率和平台管理费率计算年化
            confirmResponseDTO.setGuaranteeServiceFeeRate(confirmResponseDTO.getGuaranteeServiceFeeRate()
                    .divide(new BigDecimal(confirmResponseDTO.getLoanTerm()),MathContext.DECIMAL128).multiply(new BigDecimal(Month))
                    .setScale(PRECISION_FOUR, BigDecimal.ROUND_HALF_UP));
            confirmResponseDTO.setPlatformManageFeeRate(confirmResponseDTO.getPlatformManageFeeRate()
                    .divide(new BigDecimal(confirmResponseDTO.getLoanTerm()),MathContext.DECIMAL128).multiply(new BigDecimal(Month))
                    .setScale(PRECISION_FOUR, BigDecimal.ROUND_HALF_UP));

            if (null != projectDTO.getFullSuccessTime()) {
                //还款日期
                Calendar calendar = Calendar.getInstance();

                calendar.setTime(projectDTO.getFullSuccessTime());
                calendar.add(Calendar.MONTH, confirmResponseDTO.getLoanTerm());
                confirmResponseDTO.setRepayTime(calendar.getTime());
            }

            List<InvestUserInfoResponseDTO> infoResponseDTOS = new ArrayList<>();
            //投资人信息封装
            List<ProjectInvestOrder> projectInvestOrders = projectInvestOrderMapperExt.queryProjectInvestOrderListOrderByCreateTimeAscByProjectId(projectId);
            if (!projectInvestOrders.isEmpty()) {
                for (ProjectInvestOrder projectInvestOrder : projectInvestOrders) {
                    InvestUserInfoResponseDTO infoResponseDTO = new InvestUserInfoResponseDTO();
                    infoResponseDTO.setAmount(projectInvestOrder.getAmount());
                    infoResponseDTO.setName(projectInvestOrder.getInvestorName());
                    try {
                        infoResponseDTO.setIdCard(privacyMasks.decryptPrivacy(projectInvestOrder.getInvestorIdCard()));
                    } catch (Exception ex) {
                        log.error("借款合同投资人身份证号解密出错{}", ex);
                    }
                    infoResponseDTOS.add(infoResponseDTO);
                }
            }
            confirmResponseDTO.setResponseDTOList(infoResponseDTOS);

            return confirmResponseDTO;
        }
        return null;
    }

    /**
     * 借款确认页面的-还款详情
     *
     * @param loanConfirmRequestDTO
     * @return
     */
    public List<RepaymentPlanDTO> repaymentPlan(ConfirmLoanRepaymentPlanRequestDTO loanConfirmRequestDTO){
        log.info("借款确认页面的还款详情{}",JSONObject.toJSONString(loanConfirmRequestDTO));
        Assert.notNull(loanConfirmRequestDTO, "借款确认页面的-还款详情 build repaymentPlan loanConfirmRequestDTO is null." );

        RateConfig rateConfig = rateConfigMapperExt.queryRateConfigByDeadline(loanConfirmRequestDTO.getLoanTerm(),loanConfirmRequestDTO.getConfigType());
        return repaymentPlan(loanConfirmRequestDTO.getLoanAmount(),loanConfirmRequestDTO.getLoanTerm(),rateConfig);
    }


    private List<RepaymentPlanDTO> repaymentPlan(BigDecimal loanAmount, Integer loanTerm, RateConfig rateConfig) {
        BuildRepaymentDTO buildRepaymentDTO = new BuildRepaymentDTO();
        buildRepaymentDTO.setAmount(loanAmount);
        buildRepaymentDTO.setDeadline(loanTerm);
        buildRepaymentDTO.setYearRate(rateConfig.getBorrowInterestRate());
        buildRepaymentDTO.setGuaranteeRate(rateConfig.getGuaranteeServiceFeeRate());
        buildRepaymentDTO.setManageRate(rateConfig.getPlatformManageFeeRate());
        buildRepaymentDTO.setRepaymentType(RepaymentTypeEnum.enumOf(rateConfig.getRepaymentMode()));
        buildRepaymentDTO.setPeriodUnit(PeriodUnitEnum.MONTH);
        List<RateConfigDTO> rateConfigDTOS = new ArrayList<>();
        List<RateConfigPercent> rateConfigPercentList = rateConfigPercentMapperExt.queryConfigPercentByRateConfigId(rateConfig.getId());
        if (!rateConfigPercentList.isEmpty()) {
            for (RateConfigPercent percent : rateConfigPercentList) {
                RateConfigDTO rateConfigDTO = new RateConfigDTO();
                rateConfigDTO.setCurrentPeriod(percent.getCurrentPeriod());
                rateConfigDTO.setGuaranteeServiceFeePercent(percent.getGuaranteeServiceFeePercent());
                rateConfigDTO.setPlatformManageFeePercent(percent.getPlatformManageFeePercent());
                rateConfigDTOS.add(rateConfigDTO);
            }
        }
        return borrowerInvestorRepaymentContext.getBorrowerRepaymentPlan(buildRepaymentDTO, rateConfigDTOS);
    }


}
